﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace XuanFe.AppLaunch.ETerm
{
    public class ETermParser
    {
        Dictionary<string, string> m_month;
        Exception m_lastError;
        string m_data;
        public ETermParser(string data)
        {
            this.m_data = data;

            this.Passengers = new List<ETermPassenger>();
            this.Tickets = new List<ETermTicket>();
            this.Flights = new List<ETermFlight>();

            this.m_month = new Dictionary<string, string>();
            this.m_month.Add("JAN", "01");
            this.m_month.Add("FEB", "02");
            this.m_month.Add("MAR", "03");
            this.m_month.Add("APR", "04");
            this.m_month.Add("MAY", "05");
            this.m_month.Add("JUN", "06");
            this.m_month.Add("JUL", "07");
            this.m_month.Add("AUG", "08");
            this.m_month.Add("SEP", "09");
            this.m_month.Add("OCT", "10");
            this.m_month.Add("NOV", "11");
            this.m_month.Add("DEC", "12");
        }
        public List<ETermPassenger> Passengers { get; private set; }
        public List<ETermTicket> Tickets { get; private set; }
        public List<ETermFlight> Flights { get; private set; }
        /// <summary>
        /// 格式日期，0表示08FEB81；1表示04NOV；2表示FR04NOV
        /// </summary>
        /// <param name="t"></param>
        /// <param name="dt"></param>
        /// <param name="isFuture"></param>
        /// <returns></returns>
        private DateTime FormatDate(int t, string dt, bool isFuture)
        {
            DateTime result;
            switch (t)
            {
                case 1:
                    result = Convert.ToDateTime(string.Format("{0}-{1}-{2}", DateTime.Now.Year, this.m_month[dt.Substring(2, 3)], dt.Substring(0, 2)));
                    if (result < DateTime.Now.Date) result = result.AddYears(1);
                    return result;
                case 2:
                    result = Convert.ToDateTime(string.Format("{0}-{1}-{2}", DateTime.Now.Year, this.m_month[dt.Substring(4, 3)], dt.Substring(2, 2)));
                    if (result < DateTime.Now.Date) result = result.AddYears(1);
                    return result;
                case 0:
                default:
                    int nowYear = Convert.ToInt32(DateTime.Now.ToString("yy"));
                    int year;
                    year = Convert.ToInt32(dt.Substring(5, 2));
                    if (year > nowYear && !isFuture) year = year + 1900;
                    else year = year + 2000;
                    return Convert.ToDateTime(string.Format("{0}-{1}-{2}", year, this.m_month[dt.Substring(2, 3)], dt.Substring(0, 2)));
            }
        }
        private ETermPassenger GetPassenger(string data)
        {
            string[] ary = data.Split('/');
            string[] t = ary[0].Split(' ');
            return new ETermPassenger()
            {
                Id = ary[9],
                Airline = t[2],
                IssuringCountry = ary[1],
                PassportNo = ary[2],
                Nation = ary[3],
                Birthday = FormatDate(0, ary[4], false),
                Sex = ary[5],
                ExpiryDate = FormatDate(0, ary[6], true),
                LastName = ary[7],
                FirstName = ary[8]
            };
        }
        private ETermTicket GetTicket(string data)
        {
            string[] ary = data.Split(' ');
            string[] t = ary[7].Split('/');
            return new ETermTicket()
            {
                Airline = ary[2],
                DepartureCity = ary[4].Substring(0, 3),
                ArrivalCity = ary[4].Substring(3, 3),
                FlightNo = string.Concat(ary[2], ary[5]),
                Berth = ary[6].Substring(0, 1),
                DepartureTime = FormatDate(1, ary[6].Substring(1, 5), true),
                TicketNo = t[0],
                FlightNumber = t[1],
                Id = t[2]
            };
        }
        private ETermFlight GetFlight(string data)
        {
            string s = System.Text.RegularExpressions.Regex.Replace(data, @"\s+", " ");
            string[] ary = s.Split(' ');
            if (ary.Length <= 3) return null;
            DateTime dt = FormatDate(2, ary[2], true);
            string[] v = ary[6].Split('+');
            double d = 0;
            if (v.Length >= 2) d = Convert.ToDouble(v[1]);
            return new ETermFlight()
            {
                Airline = ary[0].Substring(0, 2),
                FlightNo = ary[0],
                Berth = ary[1],
                DepartureTime = dt.AddHours(Convert.ToDouble(ary[5].Substring(0, 2))).AddMinutes(Convert.ToDouble(ary[5].Substring(2, 2))),
                ArrivalTime = dt.AddHours(Convert.ToDouble(ary[6].Substring(0, 2))).AddMinutes(Convert.ToDouble(ary[6].Substring(2, 2))).AddDays(d),
                DepartureCity = ary[3].Substring(0, 3),
                ArrivalCity = ary[3].Substring(3, 3)
            };
        }
        public bool Parser()
        {
            try
            {
                string data = this.m_data;
                if (string.IsNullOrWhiteSpace(data)) return false;

                List<string> lines = new List<string>();

                int index = 0;
                int lineNumber = 1;
                var startIndex = index;
                int startPos = 0;
                do
                {
                    var c = data[index];
                    if (c == '.')
                    {
                        string numStr = data.Substring(startIndex, index - startIndex);
                        int num;
                        if (int.TryParse(numStr, out num))
                        {
                            if (num == lineNumber)
                            {
                                if (startPos != 0)
                                {
                                    string lineStr = data.Substring(startPos, index - (index - startIndex) - startPos - 1);
                                    lines.Add(lineStr);
                                }
                                startPos = index + 1;
                                lineNumber++;
                            }
                        }
                    }
                    if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
                    {
                        startIndex = index + 1;
                    }
                } while (++index < data.Length);

                if (lines.Count == 0)
                {
                    return false;
                }

                List<string> passenger = (from t in lines where t.StartsWith("SSR DOCS") orderby t.Substring(t.LastIndexOf('/'), t.Length - t.LastIndexOf('/')) select t.Trim()).ToList();
                this.Passengers.Clear();
                passenger.ForEach(t =>
                {
                    ETermPassenger d = GetPassenger(t);
                    if (d == null) return;
                    this.Passengers.Add(d);
                });

                List<string> ticket = (from t in lines where t.StartsWith("SSR TKNE") orderby t select t.Trim()).ToList();
                this.Tickets.Clear();
                ticket.ForEach(t =>
                {
                    ETermTicket d = GetTicket(t);
                    if (d == null) return;
                    this.Tickets.Add(d);
                });

                List<string> flight = (from t in lines where t.StartsWith("  ") select t.Trim()).ToList();
                this.Flights.Clear();
                flight.ForEach(t =>
                {
                    ETermFlight d = GetFlight(t);
                    if (d == null) return;
                    this.Flights.Add(d);
                });

                return true;
            }
            catch (Exception ex)
            {
                this.m_lastError = ex;
                return false;
            }
        }
    }
}
